using DapperExtensionsNew.Configuration;
using DapperExtensionsNew.Data;
using DapperExtensionsNew.Data.Descriptors;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

namespace DapperExtensionsNew.Queryable.Analyzers
{
	public class OrderBy : AbstractAnalyzer
	{
		protected static string BuildSort<T>(IQuery<T> query)
		{
			DbType dialect = TableCache.GetDialect(typeof(T));
			StringBuilder stringBuilder = new StringBuilder();
			if (query.OrderBys != null)
			{
				int count = query.OrderBys.Count;
				if (count > 0)
				{
					stringBuilder.Append(" ORDER BY");
				}
				List<ColumnDescriptor> columnDescriptors = TableCache.GetColumnDescriptors(typeof(T));
				for (int i = 0; i < count; i++)
				{
					Data.OrderBy sort = query.OrderBys[i];
					if (columnDescriptors.All((ColumnDescriptor n) => n.DbName != sort.OrderField))
					{
						throw new ArgumentException("query.OrderBys OrderField Not Exist");
					}
					SqlDatabaseOptions sqlDatabaseOptions = SqlDatabaseOptionsFactory.GetSqlDatabaseOptions(dialect);
					string startDelimiter = sqlDatabaseOptions.StartDelimiter;
					string endDelimiter = sqlDatabaseOptions.EndDelimiter;
					stringBuilder.Append($" {startDelimiter}{sort.OrderField}{endDelimiter} {sort.OrderDirection}");
					if (i != count - 1)
					{
						stringBuilder.Append(",");
					}
				}
				return stringBuilder.ToString();
			}
			return string.Empty;
		}

		protected override void Analyze(Context context)
		{
			MethodInfo methodInfo = typeof(OrderBy).GetMethod("BuildSort", BindingFlags.Static | BindingFlags.NonPublic)?.MakeGenericMethod(context.ModelType);
			if (methodInfo == null)
			{
				throw new ArgumentException();
			}
			BinaryExpression item = Expression.Assign(context.OrderExpression, Expression.Call(null, methodInfo, context.QueryExpression));
			context.Statements.Add(item);
		}
	}
}
